package com.killer.edu.course.remote;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.killer.edu.common.constant.CacheDefine;
import com.killer.edu.common.constant.MQConstant;
import com.killer.edu.common.mq.RocketMqService;
import com.killer.edu.common.mq.dto.BaseMqDTO;
import com.killer.edu.common.result.ResponseDTO;
import com.killer.edu.common.util.ConverUtil;
import com.killer.edu.common.util.DateUtil;
import com.killer.edu.common.util.ValidateUtils;
import com.killer.edu.course.api.CourseRemoteService;
import com.killer.edu.course.api.dto.*;
import com.killer.edu.course.api.enums.CourseLessonStatus;
import com.killer.edu.course.api.enums.CourseStatus;
import com.killer.edu.course.api.param.CourseQueryParam;
import com.killer.edu.course.entity.Course;
import com.killer.edu.course.entity.Lesson;
import com.killer.edu.course.entity.Teacher;
import com.killer.edu.course.service.ICourseService;
import com.killer.edu.course.service.ILessonService;
import com.killer.edu.course.service.IPlayHistoryService;
import com.killer.edu.course.service.ITeacherService;
import com.killer.edu.message.api.dto.LessonStatusReleaseDTO;
import com.killer.edu.order.api.UserCourseOrderRemoteService;
import com.killer.edu.order.api.dto.UserCourseOrderDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/course")
@Slf4j
public class CourseRemoteServiceImpl implements CourseRemoteService {

    @Autowired
    private ICourseService courseService;
    @Autowired
    private ITeacherService teacherService;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    private ILessonService lessonService;
    @Autowired
    private UserCourseOrderRemoteService userCourseOrderRemoteService;
    @Autowired
    private RocketMqService rocketMqService;

    //显示课时数
    private static final int SHOW_LESSON_NUM = 2;


    @Override
    @Transactional
    public boolean saveOrUpdateCourse(CourseDTO courseDTO) {
        Course course = ConverUtil.convert(courseDTO, Course.class);
        course.setUpdateTime(LocalDateTime.now());
        course.setCreateTime(LocalDateTime.now());
        log.info("保存的课程信息：{}", JSON.toJSONString(course));
        boolean res = courseService.saveOrUpdate(course);
        //查看是否有提交老师信息
        TeacherDTO teacherDTO = courseDTO.getTeacherDTO();
        if(teacherDTO == null){
            return Boolean.TRUE;
        }
        Teacher teacher=ConverUtil.convert(courseDTO.getTeacherDTO(), Teacher.class);
        teacher.setCourseId(course.getId());
        teacher.setUpdateTime(LocalDateTime.now());
        teacher.setCreateTime(LocalDateTime.now());
        log.info("保存老师的信息为 teacher:{}",JSON.toJSONString(teacher));
        teacherService.saveOrUpdate(teacher);
        return res;
    }

    @Override
    public CourseDTO getCourseById(Integer courseId) {
        Course course = courseService.getById(courseId);
        CourseDTO courseDTO= ConverUtil.convert(course, CourseDTO.class);
        //封装教师信息
        setTeacher(courseDTO);
        //封装课程活动信息
        hasActivityCourse(courseDTO);
        return courseDTO;
    }

    @Override
    public PageResultDTO<CourseDTO> getQueryCourses(CourseQueryParam courseQueryParam) {
        return null;
    }

    private void setTeacher(CourseDTO courseDTO) {
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("course_id",courseDTO.getId());
        queryWrapper.eq("is_del",Boolean.FALSE);
        List teachers = teacherService.list(queryWrapper);
        if(CollectionUtils.isEmpty(teachers)){
            return;
        }
        TeacherDTO teacherDTO = ConverUtil.convert(teachers.get(0), TeacherDTO.class);
        courseDTO.setTeacherDTO(teacherDTO);
    }

    private void hasActivityCourse(CourseDTO courseDTO) {
        String activityCourseStr = redisTemplate.opsForValue().get(CacheDefine.ActivityCourse.getKey(courseDTO.getId()));
        log.info("hasActivityCourse - activityCourseStr:{} courseId:{}",activityCourseStr,courseDTO.getId());
        if(null == activityCourseStr) {
            return;
        }
        ActivityCourseDTO activityCourseCache = JSON.parseObject(activityCourseStr, ActivityCourseDTO.class);
        if(!DateUtil.isBefore(new Date(), activityCourseCache.getBeginTime())) {
            return;
        }
        String stock = redisTemplate.opsForValue().get(CacheDefine.ActivityCourse.getStockKey(courseDTO.getId()));
        if(null == stock || Long.parseLong(stock) <= 0) {
            return;
        }
        Long time = DateUtil.getMillisecond(new Date(), activityCourseCache.getEndTime());
        if(time <= 0) {
            return;
        }
        courseDTO.setActivityCourse(true);
        courseDTO.setDiscounts(activityCourseCache.getAmount());
        courseDTO.setActivityTime(time);
    }

    public List<CourseDTO> getAllCourses(Integer userId) {
        log.info("getAllCourses - userId:{}",userId);
        // 获取有效的课程
        List<Course> courses = getInvalidCourses();
        if(CollectionUtils.isEmpty(courses)){
            log.info("[选课列表] 获取选课列表信息为空");
            return Collections.emptyList();
        }
        Map<Integer, UserCourseOrderDTO> orderMap = getUserCourseOrderMapForCourseList(userId);
        List<CourseDTO> courseDTOS = new ArrayList<>();
        for (Course course : courses) {
            CourseDTO courseDTO = ConverUtil.convert(course, CourseDTO.class);
            courseDTOS.add(courseDTO);
        }
        //未购上新课程
        List<CourseDTO> newCourseList = new LinkedList<>();
        //未购课程
        List<CourseDTO> notPayCourseList = new LinkedList<>();
        //已购课程
        List<CourseDTO> payedCourseList = new LinkedList<>();
        for (CourseDTO courseDTO : courseDTOS) {
            Integer courseId = courseDTO.getId();
            // 设置购买标识
            setBuyFlag(orderMap, courseDTO, courseId);
            // 设置老师的信息
            setTeacher(courseDTO);
            // 设置topN课时
            setTopNCourseLesson(courseDTO);
            //保存上新且未购买的课程
            if(!courseDTO.getIsBuy() && org.apache.commons.lang.StringUtils.isNotBlank(courseDTO.getDiscountsTag())){
                hasActivityCourse(courseDTO);
                newCourseList.add(courseDTO);
                continue;
            }
            //未购买课程
            if(!courseDTO.getIsBuy()){
                hasActivityCourse(courseDTO);
                notPayCourseList.add(courseDTO);
                continue;
            }
            //已购买的课程列表
            payedCourseList.add(courseDTO);

        }

        //遍历组装courseList信息
        List<CourseDTO> courseList = new LinkedList<CourseDTO>();
        courseList.addAll(newCourseList);
        courseList.addAll(notPayCourseList);
        courseList.addAll(payedCourseList);
        return courseList;
    }

    /**
     * 获取有效课程
     * @return
     */
    private List<Course> getInvalidCourses() {
        QueryWrapper courseQueryWrapper = new QueryWrapper();
        courseQueryWrapper.eq("status", CourseStatus.PUTAWAY.getCode());
        courseQueryWrapper.eq("is_del", Boolean.FALSE);
        courseQueryWrapper.orderByDesc(" sort_num ");
        return courseService.list(courseQueryWrapper);
    }


    /**
     * 获取topN课程
     * @param courseDTO
     */
    private void setTopNCourseLesson(CourseDTO courseDTO) {
        QueryWrapper lessonQueryWrapper = new QueryWrapper();
        lessonQueryWrapper.ne("status", CourseLessonStatus.HIDE.getCode());
        lessonQueryWrapper.eq("course_id",courseDTO.getId());
        lessonQueryWrapper.eq("is_del", Boolean.FALSE);
        lessonQueryWrapper.orderByAsc("section_id" ,"order_num");
        lessonQueryWrapper.last("limit 0 , " + SHOW_LESSON_NUM);
        List<LessonDTO> courseLessonDTOS = lessonService.list(lessonQueryWrapper);
        courseDTO.setTopNCourseLesson(courseLessonDTOS);
    }

    public Map<Integer, UserCourseOrderDTO> getUserCourseOrderMapForCourseList(Integer userId){
        if(userId == null){
            return new HashMap<Integer, UserCourseOrderDTO>();
        }
        List<UserCourseOrderDTO> userOrders = userCourseOrderRemoteService.getUserCourseOrderByUserId(userId);
        if(CollectionUtils.isEmpty(userOrders)){
            return new HashMap<Integer, UserCourseOrderDTO>();
        }
        return userOrders.stream().collect(Collectors.toMap(UserCourseOrderDTO::getCourseId, Function.identity()));
    }

    /**
     * 设置购买标签
     * @param orderMap
     * @param courseDTO
     * @param courseId
     */
    private void setBuyFlag(Map<Integer, UserCourseOrderDTO> orderMap, CourseDTO courseDTO, Integer courseId) {
        if(orderMap == null){
            log.info("用户没有购买课程，订单为空");
            return;
        }
        UserCourseOrderDTO order = orderMap.get(courseId);
        if(order != null){
            courseDTO.setIsBuy(Boolean.TRUE);
        }
    }

    public List<CourseDTO> getPurchasedCourse(Integer userId) {
        return Collections.EMPTY_LIST;
    }

    @Override
    @PostMapping("/changeState")
    public Boolean changeState(Integer courseId, Integer status) {
        Course course = courseService.getById(courseId);
        ValidateUtils.isTrue(null != course, "课程为空");
        course.setStatus(status);
        courseService.updateById(course);
        if (status == CourseStatus.PUTAWAY.getCode()) {
            //如果是上架，则推送信息
            rocketMqService.convertAndSend(MQConstant.Topic.LESSON_STATUS_RELEASE, new BaseMqDTO<>(courseId,UUID.randomUUID().toString()));
        }
        return true;
    }

}
